//
//  UIFont+Dynamic.swift
//  ACFrameworkSwift
//
//  Created by c5342925 on 2022/3/7.
//

import Foundation
import UIKit

/**
 Font is composed of `font-family`, `font-weight`, `font-style`, `font-size`.
 
 `UIFont.Weight` is used to set `font-weight`, optional value:  `thin, light, regular, medium, semibold, bold, heavy, black, ultraLight`
 
  `font-style` contain `italic`
 
  Note:
  - Custom font family is conflict whit UIFont.Weight, so use custom font family instead of UIFont.Weight.
 
 */

extension UIFont {
    
    /// Setting the fixed font.
    /// - Parameters:
    ///   - fontName: instace of `UIFont.FontName`, default is `.regular`.
    ///   - size: font size.
    ///   - weight: instance of `UIFont.Weight`, default is `.regular`.
    ///   - isItalic: italic or not, default is false.
    /// - Returns: instance of UIFont
    public static func preferredFixedFont(fontName: UIFont.FontName = .regular,
                                          size: CGFloat,
                                          weight: UIFont.Weight = .regular,
                                          isItalic: Bool = false) -> UIFont {
        guard var font = UIFont(name: fontName.description, size: size) else {
            var font = UIFont.systemFont(ofSize: size, weight: weight)
            if isItalic {
                font = font.italic
            }
            return font
        }
        if isItalic {
            font = font.italic
        }
        return font
    }
    
    /// Setting the dynamic font.
    /// - Parameters:
    ///   - textStyle: instance of `UIFont.TextStyle`.
    ///   - fontName: instace of `UIFont.FontName`, default is `.regular`.
    ///   - weight: instance of `UIFont.Weight`, default is `.regular`.
    ///   - isItalic:italic or not, default is false.
    /// - Returns: instance of UIFont
    public static func preferredDynamicFont(forTextStyle textStyle: UIFont.TextStyle,
                                            fontName: UIFont.FontName = .regular,
                                            weight: UIFont.Weight = .regular,
                                            isItalic: Bool = false) -> UIFont {
        
        // Less than the iOS 11, only allow system font.
        func dynamicFontSettingWhenLessThaniOS11() -> UIFont {
            var font = UIFont.preferredFont(forTextStyle: textStyle).withWeight(weight)
            if isItalic {
                font = font.italic
            }
            return font
        }
        
        guard var font = UIFont(name: fontName.description, size: textStyle.size) else {
            return dynamicFontSettingWhenLessThaniOS11()
        }
        
        if #available(iOS 11.0, *) {
            let metrics = UIFontMetrics(forTextStyle: textStyle)
            if isItalic {
                font = font.italic
            }
            let scaledFont = metrics.scaledFont(for: font)
            return scaledFont
        }
        
        return dynamicFontSettingWhenLessThaniOS11()
    }
    
}

extension UIFont {
    
    public static func registerFonts() {
        self.registerFont("72-Black", fileExtension: "ttf")
        self.registerFont("72-Bold", fileExtension: "ttf")
        self.registerFont("72-BoldItalic", fileExtension: "ttf")
        self.registerFont("72-Condensed", fileExtension: "ttf")
        self.registerFont("72-CondensedBold", fileExtension: "ttf")
        self.registerFont("72-Italic", fileExtension: "ttf")
        self.registerFont("72-Light", fileExtension: "ttf")
        self.registerFont("72-Regular", fileExtension: "ttf")
    }
    
    private static func registerFont(_ name: String, fileExtension: String, bundle: Bundle? = nil) {
        let bundlePath = Bundle.main.path(forResource: "ACFrameworkSwift", ofType: ".bundle") ?? ""
        let bd = Bundle(path: bundlePath) ?? Bundle.main
        guard let fontURL = bd.url(forResource: name, withExtension: fileExtension) else {
            print("No font named \(name).\(fileExtension) was found in the module bundle = \(bd)")
            return
        }

        var error: Unmanaged<CFError>?
        CTFontManagerRegisterFontsForURL(fontURL as CFURL, .process, &error)
        if let error = error {
            print("Error registering font: \(error)")
        } else {
            print("Successfully registered font: \(name)")
        }
    }
}

extension UIFont {
    
    /// set `font-style` to `italic`, support custom font and system font.
    var italic: UIFont {
        return with(.traitItalic)
    }
    
    /// 添加符号特征
    private func with(_ traits: UIFontDescriptor.SymbolicTraits...) -> UIFont {
        guard let descriptor = self.fontDescriptor.withSymbolicTraits(UIFontDescriptor.SymbolicTraits(traits).union(self.fontDescriptor.symbolicTraits)) else {
            return self
        }
        return UIFont(descriptor: descriptor, size: 0)
    }
    
    private func withWeight(_ weight: UIFont.Weight) -> UIFont {
        let newDescriptor = fontDescriptor.addingAttributes([.traits: [UIFontDescriptor.TraitKey.weight: weight]])
        return UIFont(descriptor: newDescriptor, size: 0)
    }
}

extension UIFont {
    
    /// Match the customized name
    public enum FontName: String {
        case black = "Black"
        case bold  = "Bold"
        case boldItalic = "BoldItalic"
        case condensed = "Condensed"
        case condensedBold = "CondensedBold"
        case italic = "Italic"
        case light = "Light"
        case regular = "Regular"
        
        var description: String {
            return "72-\(self.rawValue)"
        }
    }
}

// MARK: - Font Size

extension UIFont.TextStyle {
    /// for example define new textStyle
    // public static let newFt = UIFont.TextStyle(rawValue: "com.acframeworkswift.TextStyle.newFt")
}

extension UIFont.TextStyle {
    
    /// 根据系统的 textStyle 来匹配自定义 font number
    var size: CGFloat {
        if #available(iOS 11.0, *) {
            if self == .largeTitle {
                return 34
            }
        }
        
        switch self {
        case .title1:
            return 28
        case .title2:
            return 22
        case .title3:
            return 20
        case .headline:
            return 17
        case .body:
            return 17
        case .callout:
            return 16
        case .subheadline:
            return 15
        case .footnote:
            return 13
        case .caption1:
            return 12
        case .caption2:
            return 11
        default:
            return 14
        }
    }
}

extension UIFont.TextStyle: CustomStringConvertible {
    /// :nodoc:
    public var description: String {
        if #available(iOS 11.0, *) {
            if self == .largeTitle {
                return "largeTitle"
            }
        }
        
        switch self {
        case .title1:
            return "title1"
        case .title2:
            return "title2"
        case .title3:
            return "title3"
        case .headline:
            return "headline"
        case .body:
            return "body"
        case .callout:
            return "callout"
        case .subheadline:
            return "subheadline"
        case .footnote:
            return "footnote"
        case .caption1:
            return "caption1"
        case .caption2:
            return "caption2"
        default:
            return "Unknown"
        }
    }
}
